home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Frameworks / Sprocket Framework DR2 / Sprocket Starter / SprocketStarter Code / TextWindow.cp < prev    next >
Text File  |  1996-06-15  |  52KB  |  2,261 lines

  1. /*
  2.  
  3.     File:        TextWindow.cp
  4.     Project:    Sample code for Sprocket Framework 1.1 (DR2), released 6/15/96
  5.     Contains:    Complete WASTE based text editing window
  6.     To Do:        Squash bugs, fix Copy Paste & Undo
  7.  
  8.     Sprocket Major Contributors:
  9.     ----------------------------
  10.     Dave Falkenburg, producer of Sprocket 1.0
  11.     Bill Hayden,     producer of Sprocket 1.1
  12.     Steve Sisak,     producer of the upcoming Sprocket 2.0
  13.     
  14.     Pete Alexander        Steve Falkenburg    Randy Thelen
  15.     Eric Berdahl        Nitin Ganatra        Chris K. Thomas
  16.     Marshall Clow        Dave Hershey        Leonard Rosenthal
  17.     Tim Craycroft        Dave Mark            Dean Yu
  18.     David denBoer        Gary Powell
  19.     Cameron Esfahani    Jon Summers            Apple Computer, Inc.
  20.         
  21.     Comments, Additions, or Corrections:
  22.     ------------------------------------
  23.     Bill Hayden, Nikol Software <nikol@codewell.com>
  24.  
  25. */
  26.  
  27.  
  28. #include "StandardMenus.h"
  29. #include "Sprocket.h"
  30. #include "UDialog.h"
  31. #include "TextWindow.h"
  32. #include "UString.h"
  33. #include "UResources.h"
  34.  
  35. #include <ColorPicker.h>
  36.  
  37. #ifndef _LIMITS
  38. #include "limits.h"
  39. #endif
  40.  
  41. #ifndef __SCRAP__
  42. #include <Scrap.h>
  43. #endif
  44.  
  45. static pascal void TextScrolled( WEReference we );
  46. static pascal void ScrollProc( ControlRef bar, ControlPartCode partCode );
  47. pascal OSErr TranslateDrag( DragReference theDrag, ItemReference theItem, FlavorType requestedType, Handle dataHandle );
  48.  
  49. static short    FindMenuItemText( MenuRef menu, ConstStr255Param stringToFind );
  50. static CommandID    SelectedColor(RGBColor& theColor);
  51.  
  52. static WEScrollUPP            sWEScroller;
  53. static WETranslateDragUPP    sWEDragTranslator;
  54. static ControlActionUPP        sScrollProc;
  55. static short                sScrollStep; // how many pixels to scroll (used by ScrollProc)
  56.  
  57.  
  58. #define kTitleHeight    20        // usual height of a window title bar
  59. #define kTextMargin        3        // indent of text rect from a window port rect
  60. #define kScrollDelta    11        // pixels to scroll when the scroll bar arrow is clicked
  61.  
  62. #define kTextWindowTemplateID    2000
  63.  
  64. // kMaxDocWidth is an arbitrary number used to specify the width of the WERec's
  65. // destination rectangle so that word wrap and horizontal scrolling can be
  66. // demonstrated.
  67. enum {
  68.     kMinWindowWidth        = 200,
  69.     kMinWindowHeight    = 80,
  70.     kMaxWindowWidth        = 576
  71. };
  72.  
  73. // ScrollBarAdjust, GrowBoxAdjust, and ScrollBar width are used in calculating
  74. // values for control positioning and sizing.
  75. const short kScrollbarAdjust = 15;
  76.  
  77. MenuRef            TTextWindow::fFontMenu;
  78. MenuRef            TTextWindow::fSizeMenu;
  79. MenuRef            TTextWindow::fStyleMenu;
  80. MenuRef            TTextWindow::fColorMenu;
  81.  
  82.  
  83.  
  84.  
  85. /**********************************************************************************/
  86.  
  87.  
  88.  
  89.  
  90. // notice that we pass the resID parameter up to our base class,
  91. // which actually creates the window for us
  92. TTextWindow::TTextWindow(void)
  93. {
  94.     //fTemplateID = ResID;
  95.     
  96.     fDocVScroll = fDocHScroll = nil;
  97.     fWEHandle = nil;
  98.     
  99.     fToolbarHeight = 60;
  100.     
  101.     SetUpStaticMenu();        // CreateWindow will call Activate(), so we must do this first
  102. }
  103.  
  104.  
  105.  
  106. /**********************************************************************************/
  107.  
  108.  
  109.  
  110. OSErr    TTextWindow::ITextWindow(FSSpecPtr filespec)
  111. {
  112.     LongRect        destRect, viewRect;
  113.     Rect            boundsRect;
  114.     OSErr            err;
  115.     short            weFlags;
  116.  
  117.  
  118.     pcpy(this->fName, "\pUntitled");
  119.     
  120.     if (filespec)
  121.         {
  122.         this->fBackingFile = new TFile(*filespec);
  123.         pcpy(this->fName, filespec->name);
  124.         }
  125.     else
  126.         {
  127.         this->fBackingFile = new TFile;
  128.         pcpy(this->fName, "\pUntitled");
  129.         }
  130.         
  131.     if (!this->fBackingFile)
  132.         return fnfErr;
  133.             
  134.     this->CreateWindow(kNormalWindow);
  135.     if (!fWindow)
  136.         return memFullErr;
  137.         
  138.     SetWTitle(fWindow, fName);
  139.     
  140.     SetPortWindowPort(fWindow);            /*    Do this first, or else    */
  141.     
  142.     GetWERect(viewRect);
  143.     GetWERect(destRect);
  144.  
  145.     destRect.right = destRect.left + kMaxWindowWidth;
  146.     
  147.     weFlags =    weDoAutoScroll + 
  148.                 weDoUndo +
  149.                 weDoIntCutAndPaste +
  150.                 weDoUseTempMem +
  151.                 weDoDrawOffscreen;
  152.                 
  153.     if (gHasDragManager)
  154.         weFlags += weDoDragAndDrop + weDoOutlineHilite;
  155.     
  156.     err = WENew( &destRect, &viewRect, weFlags, &fWEHandle);
  157.     if ( err != noErr )
  158.         return err;
  159.         
  160.     WESetAlignment( weFlushLeft, fWEHandle );    
  161.  
  162.     //    save a reference to the window in the WE instance
  163.     err = WESetInfo( weRefCon, &this, fWEHandle );
  164.     if ( err != noErr )
  165.         return err;
  166.  
  167.     if ( sWEScroller == NULL )
  168.         {
  169.         sWEScroller = NewWEScrollProc( TextScrolled );
  170.         
  171.         if (gHasDragManager)
  172.             sWEDragTranslator = NewWETranslateDragProc( TranslateDrag );
  173.         }
  174.     
  175.     //    set up our callbacks
  176.     
  177.     err = WESetInfo( weScrollProc, &sWEScroller, fWEHandle );
  178.     if ( err != noErr )
  179.         return err;
  180.     
  181.     if (gHasDragManager)
  182.         {
  183.         err = WESetInfo( weTranslateDragHook, &sWEDragTranslator, fWEHandle );
  184.         if ( err != noErr )
  185.             return err;
  186.         }
  187.  
  188.     WEActivate(fWEHandle);
  189.     
  190.     
  191.     // get scrollbars
  192.     
  193.     boundsRect = GetContentsBounds();
  194.     
  195.     LocalToGlobal((Point*) &boundsRect.top);
  196.     LocalToGlobal((Point*) &boundsRect.bottom);
  197.  
  198.     boundsRect.left = boundsRect.right - kScrollbarAdjust;
  199.     boundsRect.bottom -= kScrollbarAdjust - 1;
  200.     boundsRect.top = -1 + fToolbarHeight;
  201.     boundsRect.right++;
  202.     fDocVScroll = NewControl(fWindow, &boundsRect, "\p", true, 0, 0, 0, scrollBarProc, 0);
  203.     
  204.     if (!fDocVScroll)
  205.         return 2;
  206.  
  207.     boundsRect = GetContentsBounds();
  208.     
  209.     LocalToGlobal((Point*) &boundsRect.top);
  210.     LocalToGlobal((Point*) &boundsRect.bottom);
  211.  
  212.     boundsRect.top = boundsRect.bottom - kScrollbarAdjust;
  213.     boundsRect.right -= kScrollbarAdjust - 1;
  214.     boundsRect.left = -1;
  215.     boundsRect.bottom++;
  216.     fDocHScroll = NewControl(fWindow, &boundsRect, "\p", true, 0, 0, 0, scrollBarProc, 0);
  217.     
  218.     if (!fDocHScroll)
  219.         return 3;
  220.  
  221.  
  222.     // install buttons in toolbar
  223.     
  224.     SetRect(&boundsRect, 10, 8, 42, 40);
  225.     fSaveButton = NewControl(fWindow, &boundsRect, "\pSave…", true, 1000, 0, 0, 609, cSave);
  226.     
  227.     
  228.     SetRect(&boundsRect, 150, 7, 166, 19);
  229.     fPlainButton = NewControl(fWindow, &boundsRect, "\p", true, 1010, 0, 0, 608, cPlainText);
  230.     
  231.     OffsetRect(&boundsRect, 20, 0);
  232.     fBoldButton = NewControl(fWindow, &boundsRect, "\p", true, 1011, 0, 0, 608, cBold);
  233.  
  234.     OffsetRect(&boundsRect, 20, 0);
  235.     fItalicButton = NewControl(fWindow, &boundsRect, "\p", true, 1012, 0, 0, 608, cItalic);
  236.  
  237.     OffsetRect(&boundsRect, 20, 0);
  238.     fUnderlineButton = NewControl(fWindow, &boundsRect, "\p", true, 1013, 0, 0, 608, cUnderline);
  239.  
  240.  
  241.     SetRect(&boundsRect, 150, 23, 166, 35);
  242.     fLeftAlignButton = NewControl(fWindow, &boundsRect, "\p", true, 1002, 0, 0, 608, cAlignLeft);
  243.     
  244.     OffsetRect(&boundsRect, 20, 0);
  245.     fCenterAlignButton = NewControl(fWindow, &boundsRect, "\p", true, 1004, 0, 0, 608, cAlignCenter);
  246.  
  247.     OffsetRect(&boundsRect, 20, 0);
  248.     fRightAlignButton = NewControl(fWindow, &boundsRect, "\p", true, 1003, 0, 0, 608, cAlignRight);
  249.  
  250.     OffsetRect(&boundsRect, 20, 0);
  251.     fJustifyButton = NewControl(fWindow, &boundsRect, "\p", true, 1005, 0, 0, 608, cAlignJustify);
  252.  
  253.  
  254.     SetRect(&boundsRect, 150, 39, 166, 51);
  255.     fBlackButton = NewControl(fWindow, &boundsRect, "\p", true, 1020, 0, 0, 608, cBlack);
  256.     
  257.     OffsetRect(&boundsRect, 20, 0);
  258.     fBlueButton = NewControl(fWindow, &boundsRect, "\p", true, 1021, 0, 0, 608, cBlue);
  259.  
  260.     OffsetRect(&boundsRect, 20, 0);
  261.     fGreenButton = NewControl(fWindow, &boundsRect, "\p", true, 1022, 0, 0, 608, cGreen);
  262.  
  263.     OffsetRect(&boundsRect, 20, 0);
  264.     fRedButton = NewControl(fWindow, &boundsRect, "\p", true, 1023, 0, 0, 608, cRed);
  265.     
  266.     OffsetRect(&boundsRect, 20, 0);
  267.     fPinkButton = NewControl(fWindow, &boundsRect, "\p", true, 1024, 0, 0, 608, cPink);
  268.  
  269.     OffsetRect(&boundsRect, 20, 0);
  270.     fOrangeButton = NewControl(fWindow, &boundsRect, "\p", true, 1025, 0, 0, 608, cOrange);
  271.  
  272.     OffsetRect(&boundsRect, 20, 0);
  273.     fBrownButton = NewControl(fWindow, &boundsRect, "\p", true, 1026, 0, 0, 608, cBrown);
  274.  
  275.     
  276.     err = LCAttach( fDocVScroll );
  277.     if ( err != noErr )
  278.         return err;
  279.  
  280.     err = LCAttach( fDocHScroll );
  281.     if ( err != noErr )
  282.         return err;
  283.  
  284.     this->ViewChanged();
  285.     this->AdjustBars();
  286.     this->ScrollBarChanged();
  287.  
  288.     ShowWindow(fWindow);
  289.     
  290.     this->Activate(true);
  291.     this->Draw();
  292.     
  293.     return noErr;
  294. }
  295.  
  296.  
  297.  
  298. /**********************************************************************************/
  299.  
  300.  
  301.  
  302.  
  303. TTextWindow::~TTextWindow()
  304. {
  305.     if ( fWEHandle != nil )
  306.         {
  307.         WEDispose(fWEHandle);            // dispose the WEHandle if we got far enough to make one
  308.         }
  309.         
  310.     delete this->fBackingFile;
  311.     
  312.     SetCursor(&qd.arrow);                // if the user closed the window while in the text area
  313. }
  314.  
  315.  
  316.  
  317.  
  318. /**********************************************************************************/
  319.  
  320.  
  321.  
  322.  
  323. Boolean TTextWindow::Close(void)
  324. {
  325.     Boolean retVal;
  326.     
  327.     if ( fDocVScroll != nil )
  328.         {
  329.         LCDetach(fDocVScroll);
  330.         }
  331.         
  332.     if ( fDocHScroll != nil )
  333.         {
  334.         LCDetach(fDocHScroll);
  335.         }
  336.     
  337.     retVal = TWindow::Close();
  338.     
  339.     if ( retVal )    // in case we are the last TTextWindow open, disable all the edit commands
  340.         {
  341.         gMenuBar->EnableCommand ( cUndo,        false );
  342.         gMenuBar->EnableCommand ( cCut,            false );
  343.         gMenuBar->EnableCommand ( cCopy,        false );
  344.         gMenuBar->EnableCommand ( cPaste,        false );
  345.         gMenuBar->EnableCommand ( cClear,        false );
  346.         gMenuBar->EnableCommand ( cSelectAll,    false );
  347.         }
  348.         
  349.     return retVal;
  350. }
  351.  
  352.  
  353.  
  354. /**********************************************************************************/
  355.  
  356.  
  357.  
  358. WindowRef TTextWindow::MakeNewWindow(WindowRef behindWindow)
  359. {
  360.     return GetNewColorOrBlackAndWhiteWindow( kTextWindowTemplateID, nil, behindWindow );
  361. }
  362.  
  363.  
  364.  
  365.  
  366. /**********************************************************************************/
  367.  
  368.  
  369.  
  370.  
  371. // Called when a mouseDown occurs in the grow box of an active window.
  372.  
  373. void TTextWindow::AdjustForNewWindowSize(Rect* oldRect, Rect* newRect)
  374. {
  375.     GrafPtr            savePort;
  376.     Rect            r;
  377.     RgnHandle        tempRgn, dirtyRgn;
  378.     
  379.     GetPort( &savePort );
  380.     SetPortWindowPort( fWindow );
  381.     
  382.     //    create temporarty regions for calculations
  383.     tempRgn = NewRgn();
  384.     dirtyRgn = NewRgn();
  385.  
  386.     //    save old text region
  387.     
  388.     GetTextRect( &r );
  389.     RectRgn( tempRgn, &r );
  390.         
  391.     //    erase the old grow icon rect
  392.     SetRect(&r, oldRect->right - 15, oldRect->bottom - 15, oldRect->right, oldRect->bottom);
  393.     InvalRect( &r );
  394.     
  395.     //    hide the scroll bars
  396.     
  397.     HideControl( fDocVScroll );
  398.     HideControl( fDocHScroll );
  399.     
  400.     //    perform the actual resizing of the window, redraw scroll bars and grow icon
  401.     this->ViewChanged();
  402.     
  403.     //    calculate the dirty region (to be updated)
  404.     SetRect(&r, oldRect->left, oldRect->top, oldRect->right - kScrollbarWidth - kTextMargin,
  405.                                              oldRect->bottom - kScrollbarWidth - kTextMargin);
  406.     RectRgn( tempRgn, &r );
  407.     RectRgn( dirtyRgn, newRect );
  408.     DiffRgn(dirtyRgn, tempRgn, dirtyRgn);
  409.     
  410.     //    mark the dirty region as invalid
  411.     
  412.     InvalRgn( dirtyRgn );
  413.     
  414.     GetTextRect( &r );
  415.     RectRgn( tempRgn, &r );
  416.     InsetRect(&r, -kTextMargin, -kTextMargin);
  417.     RectRgn( dirtyRgn, &r );
  418.     DiffRgn(dirtyRgn, tempRgn, dirtyRgn);
  419.     EraseRgn(dirtyRgn);
  420.  
  421.     //    throw away temporary regions
  422.     DisposeRgn( tempRgn );
  423.     DisposeRgn( dirtyRgn );
  424.     
  425.     SetPort( savePort );
  426. }
  427.  
  428.  
  429.  
  430. /**********************************************************************************/
  431.  
  432.  
  433.  
  434. void TTextWindow::ViewChanged( void )
  435. {
  436.     GrafPtr            savePort;
  437.     ControlRef        bar;
  438.     Rect            r;
  439.     LongRect        viewRect;
  440.     
  441.     GetPort( &savePort );
  442.     SetPortWindowPort( fWindow );
  443.     
  444.     //    resize the text area
  445.     
  446.     GetTextRect( &r );
  447.     WERectToLongRect( &r, &viewRect );
  448.     WESetViewRect( &viewRect, fWEHandle );
  449.     
  450.     //    move and resize the control bars
  451.     //    first, the vertical bar
  452.     
  453.     bar = fDocVScroll;
  454.     GetScrollBarRect( v, &r );
  455.     MoveControl( bar, r.left, r.top );
  456.     SizeControl( bar, r.right - r.left, r.bottom - r.top );
  457.     ValidRect( &r );
  458.     
  459.     //    now the horizontal bar
  460.     
  461.     bar = fDocHScroll;
  462.     GetScrollBarRect( h, &r );
  463.     MoveControl( bar, r.left, r.top );
  464.     SizeControl( bar, r.right - r.left, r.bottom - r.top );
  465.     ValidRect( &r );
  466.     
  467.     //    reset the thumb positions and the max values of the control bars
  468.     this->AdjustBars();
  469.     
  470.     //    redraw the control bars
  471.     ShowControl( fDocVScroll );
  472.     ShowControl( fDocHScroll );
  473.     
  474.     //    redraw the grow icon
  475.     DrawJustTheGrowIcon(fWindow);
  476.     
  477.     SetPort( savePort );
  478. }
  479.  
  480.  
  481.  
  482.  
  483. /**********************************************************************************/
  484.  
  485.  
  486.  
  487.  
  488. void TTextWindow::AdjustBars(void)
  489. {
  490.     GrafPtr            savePort;
  491.     LongRect        viewRect, destRect;
  492.     long            value;
  493.     long            max;
  494.     ControlRef        bar;
  495.     
  496.     GetPort( &savePort );
  497.     SetPortWindowPort( fWindow );
  498.     
  499.     // get the view and destination rectangle
  500.     
  501.     WEGetViewRect( &viewRect, fWEHandle );
  502.     WEGetDestRect( &destRect, fWEHandle );
  503.         
  504.     //    do the vertical axis
  505.     
  506.     //    get scroll bar handle
  507.     
  508.     bar = fDocVScroll;
  509.     
  510.     //    calculate new scroll bar settings
  511.     
  512.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  513.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  514.     
  515.     value = viewRect.top - destRect.top;
  516.     
  517.     max = value + (destRect.bottom - viewRect.bottom);
  518.     
  519.     //    make sure max is always non-negative
  520.     
  521.     if ( max <= 0 )
  522.         max = 0;
  523.         
  524.     //    reset the scroll bar
  525.     
  526.     LCSetMax( bar, max );
  527.     LCSetValue( bar, value );
  528.     
  529.     //    if value exceeds max then the bottom of the destRect is above
  530.     //    the bottom of the view rectangle:  we need to scroll the text downward
  531.     
  532.     if ( value > max )
  533.         ScrollBarChanged();
  534.     
  535.     //    now do the horizontal axis
  536.     
  537.         //    get scroll bar handle
  538.     
  539.     bar = fDocHScroll;
  540.     
  541.     //    calculate new scroll bar settings
  542.     
  543.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  544.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  545.     
  546.     value = viewRect.left - destRect.left;    
  547.     
  548.     max = value + (destRect.right - viewRect.right);
  549.     
  550.     //    make sure max is always non-negative
  551.     
  552.     if ( max <= 0 )
  553.         max = 0;
  554.         
  555.     //    reset the scroll bar
  556.     
  557.     LCSetMax( bar, max );
  558.     LCSetValue( bar, value );
  559.     
  560.     //    if value exceeds max then the bottom of the destRect is above
  561.     //    the bottom of the view rectangle:  we need to scroll the text downward
  562.     
  563.     if ( value > max )
  564.         ScrollBarChanged();
  565.     
  566.     SetPort( savePort );
  567. }
  568.  
  569.  
  570.  
  571. /**********************************************************************************/
  572.  
  573.  
  574.  
  575. void TTextWindow::ScrollBarChanged( void )
  576. {
  577.     // scroll text to reflect new scroll bar setting
  578.  
  579.     LongRect    viewRect, destRect;
  580.     
  581.     WEGetViewRect( &viewRect, fWEHandle );
  582.     WEGetDestRect( &destRect, fWEHandle );
  583.  
  584.     WEScroll( viewRect.left - destRect.left - LCGetValue(fDocHScroll),
  585.                 viewRect.top - destRect.top - LCGetValue(fDocVScroll), fWEHandle );
  586. }
  587.  
  588.  
  589.  
  590. /**********************************************************************************/
  591.  
  592.  
  593.  
  594. void TTextWindow::GetWindowSizeLimits(Rect *limits)
  595. {
  596.     limits->top = kMinWindowHeight + fToolbarHeight;
  597.     limits->left = kMinWindowWidth;
  598.     limits->right = kMaxWindowWidth;
  599.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  600. }
  601.  
  602.  
  603. /**********************************************************************************/
  604.  
  605.  
  606.  
  607. void TTextWindow::GetPerfectWindowSize(Rect * perfectSize)
  608. {
  609.     perfectSize->top = 0;
  610.     perfectSize->left = 0;
  611.     perfectSize->right = kMaxWindowWidth;
  612.     perfectSize->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  613. }
  614.  
  615.  
  616.  
  617.  
  618. /**********************************************************************************/
  619.  
  620.  
  621.  
  622.  
  623. Boolean TTextWindow::CanClose(Boolean quitting)
  624. {
  625.     SetCursor(&qd.arrow);    // in case the user hit cmd-W while over the text area
  626.     
  627.     if (WEGetModCount(fWEHandle) > 0)    // > 0 means that doc is dirty
  628.         {
  629.         Str255    s1, s3;
  630.         short reply;
  631.         
  632.         GetIndString(s1, 200, 1);
  633.         GetIndString(s3, kStandardCloseStrings, quitting ? kQuittingStr : kClosingStr);
  634.         ParamText(s1, this->fName, s3, "\p");
  635.         
  636.         reply = StandardAlert(kStandardCloseAlertID, 1, 2);
  637.         
  638.         switch (reply)
  639.             {
  640.             case 3:        // Don't Save
  641.                 return true;
  642.                 break;
  643.                     
  644.             case 2:        // Cancel
  645.                 return false;
  646.                 break;
  647.                 
  648.             case 1:        // OK (i.e. save the document)
  649.                 GetIndString(s1, 200, 3);
  650.                 ParamText(s1, "\p", "\p", "\p");
  651.                 this->DoCommand(cSave);
  652.                 break;
  653.             }
  654.         }
  655.  
  656.     return true;
  657. }
  658.  
  659.  
  660.  
  661. /**********************************************************************************/
  662.  
  663.  
  664.  
  665. void TTextWindow::Click(EventRecord * anEvent)
  666. {
  667.     long        command;
  668.     ControlRef    theControl;
  669.     Point        hitPt = anEvent->where;
  670.     
  671.     this->Select();        // so we don't have to call the inherited class
  672.     
  673.     SetPortWindowPort(fWindow);
  674.     
  675.     GlobalToLocal(&hitPt);
  676.     
  677.     FindControl(hitPt, fWindow, &theControl);
  678.     
  679.     if (theControl)
  680.         {
  681.         command = GetControlReference(theControl);
  682.         if (command != 0)
  683.             {
  684.             if ( TrackControl(theControl, anEvent->where, nil) )
  685.                 QueueCommand(command);
  686.             }
  687.         }
  688. }
  689.  
  690.  
  691.  
  692.  
  693. /**********************************************************************************/
  694.  
  695.  
  696.  
  697.  
  698. Boolean TTextWindow::EventFilter(EventRecord* theEvent)
  699. {
  700.     Rect            textRect;
  701.     GrafPtr            savePort;
  702.     Boolean            result = false; // false means click should not activate this window
  703.     Point            hitPt;
  704.  
  705.  
  706.     if ( theEvent->what != mouseDown )
  707.         {
  708.         return TWindow::EventFilter(theEvent);
  709.         }
  710.     
  711.     hitPt = theEvent->where;                            // get the click position
  712.     
  713.     if (!IsPointInContentRgn(hitPt))
  714.         {
  715.         return TWindow::EventFilter(theEvent);
  716.         }
  717.     
  718.     
  719.     //    set the port to our window's port
  720.     
  721.     GetPort( &savePort );
  722.     SetPortWindowPort(fWindow);
  723.  
  724.     GlobalToLocal( &hitPt );
  725.  
  726.  
  727.     // filter out clicks in the toolbar
  728.     
  729.     textRect = GetContentsBounds();
  730.     
  731.     GlobalToLocal((Point*) &textRect.top);
  732.     GlobalToLocal((Point*) &textRect.bottom);
  733.  
  734.     textRect.bottom = textRect.top + fToolbarHeight;
  735.     
  736.     if (PtInRect(hitPt, &textRect))        //  this is the toolbar, I'm just using textrect for convenience
  737.         {
  738.         this->Click(theEvent);
  739.         return true;
  740.         }                
  741.     
  742.  
  743.     //    convert the point to local coordinates
  744.         
  745.     GetGrowIconRect( &textRect );
  746.     if (PtInRect(hitPt, &textRect))        //  this is the growrect, I'm just using textrect for convenience
  747.         {
  748.         return TWindow::EventFilter(theEvent);
  749.         }                
  750.     
  751.     //    a click in an inactive window should normally activate it,
  752.     //    but the availability of the Drag Manager introduces an exception to this rule:
  753.     //    a click in the background selection may start a drag gesture,
  754.     //    without activating the window
  755.     
  756.     GetTextRect( &textRect );
  757.         
  758.     if ( PtInRect( hitPt, &textRect ) )
  759.         WEClick( hitPt, theEvent->modifiers, theEvent->when, fWEHandle );
  760.     else
  761.         DoScrollBar( hitPt, theEvent->modifiers );
  762.     
  763.     //    restore the port
  764.     
  765.     SetPort( savePort );
  766.     
  767.     return true;
  768. }
  769.  
  770.  
  771.  
  772. /**********************************************************************************/
  773.  
  774.  
  775.  
  776.  
  777. void TTextWindow::KeyDown(EventRecord* theEvent)
  778. {
  779.     SignedByte        keyCode;
  780.     char            key;
  781.     
  782.     keyCode = ( theEvent->message & keyCodeMask ) >> 8;
  783.     key = (char) (theEvent->message & charCodeMask);
  784.     
  785.     switch ( keyCode )
  786.         {
  787.         case keyPgUp:
  788.         case keyPgDn:
  789.         case keyHome:
  790.         case keyEnd:
  791.             DoScrollKey( keyCode );        // page movement keys are handled by DoScrollKey()
  792.         break;
  793.         
  794.         default:
  795.             WEKey( key, theEvent->modifiers, fWEHandle );
  796.         break;
  797.         }
  798.     
  799.     return;
  800. }
  801.  
  802.  
  803.  
  804. /**********************************************************************************/
  805.  
  806.  
  807.  
  808. void TTextWindow::Activate(Boolean activating)
  809. {
  810.     GrafPtr                savePort;
  811.     ControlPartCode        barHilite;
  812.  
  813.  
  814.     TWindow::Activate(activating);
  815.     
  816.     if (!fWEHandle)
  817.         return;    // caveat coder: this routine can be called before fWEHandle is even created
  818.     
  819.     GetPort( &savePort );
  820.     SetPortWindowPort( fWindow );
  821.  
  822.     // activate or deactivate the text (and any other relevant stuff) depending on just
  823.     // what we're doing here...
  824.     
  825.  
  826.     if ( activating )
  827.         {
  828.         WEActivate( fWEHandle );
  829.         barHilite = kControlNoPart;
  830.         
  831.         InsertMenu( fFontMenu, 0 );
  832.         InsertMenu( fSizeMenu, 0 );
  833.         InsertMenu( fStyleMenu, 0 );
  834.         InsertMenu( fColorMenu, 0 );
  835.         }
  836.     else
  837.         {
  838.         WEDeactivate( fWEHandle );
  839.         barHilite = kControlDisabledPart;
  840.         
  841.         DeleteMenu( mFont );
  842.         DeleteMenu( mSize );
  843.         DeleteMenu( mStyle );
  844.         DeleteMenu( mColor );
  845.         }
  846.         
  847.     gMenuBar->Invalidate();
  848.  
  849.  
  850.     //    redraw the scroll bars with the new highlighting (and validate their rects)
  851.     
  852.     HiliteControl( fDocVScroll, barHilite );
  853.     HiliteControl( fDocHScroll, barHilite );
  854.     
  855.     DrawJustTheGrowIcon(fWindow);    // This does the "right thing" whether hiliting or unhiliting
  856.     
  857.     SetPort(savePort);
  858. }
  859.  
  860.  
  861.  
  862. /**********************************************************************************/
  863.  
  864.  
  865.  
  866. void TTextWindow::Idle(EventRecord* /*anEvent*/)
  867. {
  868.     WEStyleMode        mode;
  869.     WEAlignment        alignment;
  870.     TextStyle        ts;
  871.     Boolean            temp;
  872.     
  873.  
  874.     WEIdle(nil, fWEHandle);
  875.     
  876.     if (fSaveButton)
  877.         HiliteControl( fSaveButton, WEGetModCount(fWEHandle) ? 0 : 255 );
  878.  
  879.     mode = weDoFace + weDoColor;  // query about all attributes
  880.     temp = WEContinuousStyle( &mode, &ts, fWEHandle );
  881.  
  882.     if ( mode & weDoFace )
  883.         {
  884.         HiliteControl( fPlainButton, ( ts.tsFace == 0 ) ? kControlButtonPart : 0 );
  885.         HiliteControl( fBoldButton, ( ts.tsFace & bold ) ? kControlButtonPart : 0 );
  886.         HiliteControl( fItalicButton, ( ts.tsFace & italic ) ? kControlButtonPart : 0 );
  887.         HiliteControl( fUnderlineButton, ( ts.tsFace & underline ) ? kControlButtonPart : 0 );
  888.         }
  889.     else
  890.         {
  891.         HiliteControl( fPlainButton, 0 );
  892.         HiliteControl( fBoldButton, 0 );
  893.         HiliteControl( fItalicButton, 0 );
  894.         HiliteControl( fUnderlineButton, 0 );
  895.         }
  896.         
  897.     alignment = WEGetAlignment( fWEHandle );
  898.     HiliteControl( fLeftAlignButton, ( alignment == weFlushLeft ) ? kControlButtonPart : 0 );
  899.     HiliteControl( fCenterAlignButton, ( alignment == weCenter ) ? kControlButtonPart : 0 );
  900.     HiliteControl( fRightAlignButton, ( alignment == weFlushRight ) ? kControlButtonPart : 0 );
  901.     HiliteControl( fJustifyButton, ( alignment == weJustify ) ? kControlButtonPart : 0 );
  902.  
  903.     if ( mode & weDoColor )
  904.         {
  905.         CommandID color = SelectedColor(ts.tsColor);
  906.         
  907.         HiliteControl( fBlackButton, ( color == cBlack ) ? kControlButtonPart : 0 );
  908.         HiliteControl( fBlueButton, ( color == cBlue ) ? kControlButtonPart : 0 );
  909.         HiliteControl( fGreenButton, ( color == cGreen ) ? kControlButtonPart : 0 );
  910.         HiliteControl( fRedButton, ( color == cRed ) ? kControlButtonPart : 0 );
  911.         HiliteControl( fPinkButton, ( color == cPink ) ? kControlButtonPart : 0 );
  912.         HiliteControl( fOrangeButton, ( color == cOrange ) ? kControlButtonPart : 0 );
  913.         HiliteControl( fBrownButton, ( color == cBrown ) ? kControlButtonPart : 0 );
  914.         }
  915.     else
  916.         {
  917.         HiliteControl( fBlackButton, 0 );
  918.         HiliteControl( fBlueButton, 0 );
  919.         HiliteControl( fGreenButton, 0 );
  920.         HiliteControl( fRedButton, 0 );
  921.         HiliteControl( fPinkButton, 0 );
  922.         HiliteControl( fOrangeButton, 0 );
  923.         HiliteControl( fBrownButton, 0 );
  924.         }
  925. }
  926.  
  927.  
  928.  
  929.  
  930. /**********************************************************************************/
  931.  
  932.  
  933.  
  934.  
  935. void TTextWindow::Draw(void)
  936. {
  937.     Rect        bounds = GetContentsBounds();
  938.     Rect        toolbarBounds;
  939.     RgnHandle    boundsRgn = NewRgn();
  940.     
  941.     TWindow::Draw();
  942.  
  943.     GlobalToLocal((Point*) &bounds.top);
  944.     GlobalToLocal((Point*) &bounds.bottom);
  945.     
  946.     if (fToolbarHeight > 0)
  947.         {
  948.         RGBColor myBackColor = { kAppleGrayscale2, kAppleGrayscale2, kAppleGrayscale2 };
  949.  
  950.         toolbarBounds = bounds;
  951.         toolbarBounds.bottom = toolbarBounds.top + fToolbarHeight;
  952.         
  953.         // Draw Toolbar Background
  954.         
  955.         RGBBackColor(&myBackColor);
  956.         
  957.         EraseRect(&toolbarBounds);
  958.         
  959.         MoveTo(0, fToolbarHeight - 1);
  960.         LineTo(toolbarBounds.right, fToolbarHeight - 1);
  961.         
  962.         MoveTo(0, fToolbarHeight - 3);
  963.         LineTo(toolbarBounds.right, fToolbarHeight - 3);
  964.         
  965.         Draw1Control(fSaveButton);
  966.         
  967.         TextSize(9);
  968.         TextFont(applFont);
  969.         TextFace(condense);
  970.         
  971.         MoveTo(122, 18);
  972.         DrawString("\pStyle:");
  973.  
  974.         Draw1Control(fPlainButton);
  975.         Draw1Control(fBoldButton);
  976.         Draw1Control(fItalicButton);
  977.         Draw1Control(fUnderlineButton);
  978.         
  979.         MoveTo(105, 34);
  980.         DrawString("\pAlignment:");
  981.  
  982.         Draw1Control(fLeftAlignButton);
  983.         Draw1Control(fCenterAlignButton);
  984.         Draw1Control(fRightAlignButton);
  985.         Draw1Control(fJustifyButton);
  986.         
  987.         MoveTo(122, 50);
  988.         DrawString("\pColor:");
  989.         
  990.         Draw1Control(fBlackButton);
  991.         Draw1Control(fBlueButton);
  992.         Draw1Control(fGreenButton);
  993.         Draw1Control(fRedButton);
  994.         Draw1Control(fPinkButton);
  995.         Draw1Control(fOrangeButton);
  996.         Draw1Control(fBrownButton);
  997.  
  998.         BackColor(whiteColor);
  999.         }
  1000.  
  1001.     bounds.right -= kScrollbarAdjust;
  1002.     bounds.bottom -= kScrollbarAdjust;
  1003.     bounds.top += fToolbarHeight;
  1004.     EraseRect(&bounds);
  1005.     RectRgn(boundsRgn, &bounds);
  1006.     WEUpdate(boundsRgn, fWEHandle);
  1007.     
  1008.     GetWindowContentRgn(fWindow, boundsRgn);    // recycle boundsRgn
  1009.     UpdateControls(fWindow, boundsRgn);
  1010.         
  1011.     DisposeRgn(boundsRgn);
  1012.  
  1013.     DrawJustTheGrowIcon(fWindow);
  1014. }
  1015.  
  1016.  
  1017.  
  1018. /**********************************************************************************/
  1019.  
  1020.  
  1021.  
  1022.  
  1023. void TTextWindow::AdjustCursor(EventRecord* anEvent)
  1024. {
  1025.     Rect    textBox;
  1026.     Point    where = anEvent->where;
  1027.     
  1028.     SetPortWindowPort(fWindow);
  1029.     
  1030.     GetTextRect(&textBox);
  1031.     GlobalToLocal(&where);
  1032.     if ( PtInRect(where, &textBox) )
  1033.         {
  1034.         SetCursor(*GetCursor(iBeamCursor));
  1035.         }
  1036.     else
  1037.         {
  1038.         SetCursor(&qd.arrow);
  1039.         }
  1040.     
  1041. }
  1042.  
  1043.  
  1044.  
  1045.  
  1046. /**********************************************************************************/
  1047.  
  1048.  
  1049.  
  1050. void TTextWindow::SetUpStaticMenu( void )
  1051. {
  1052.     // We only need 1 copy!
  1053.     
  1054.     if (!TTextWindow::fFontMenu)
  1055.         {
  1056.         TTextWindow::fFontMenu = GetMenu( mFont );
  1057.         if (TTextWindow::fFontMenu)
  1058.             {
  1059.             AppendResMenu(TTextWindow::fFontMenu, 'FONT');
  1060.             InsertMenu(TTextWindow::fFontMenu, 0);
  1061.             }
  1062.         }
  1063.  
  1064.     if (!TTextWindow::fSizeMenu)
  1065.         {
  1066.         TTextWindow::fSizeMenu = gMenuBar->GetMenuFromCMNU( mSize );
  1067.         }
  1068.         
  1069.     if (!TTextWindow::fStyleMenu)
  1070.         {
  1071.         TTextWindow::fStyleMenu = gMenuBar->GetMenuFromCMNU( mStyle );
  1072.         }
  1073.         
  1074.     if (!TTextWindow::fColorMenu)
  1075.         {
  1076.         TTextWindow::fColorMenu = gMenuBar->GetMenuFromCMNU( mColor );
  1077.         }
  1078. }
  1079.  
  1080.  
  1081.  
  1082. /**********************************************************************************/
  1083.  
  1084.  
  1085.  
  1086.  
  1087. void TTextWindow::AdjustMenusBeforeMenuSelection(void)
  1088. {
  1089.     WEStyleMode        mode;
  1090.     WEAlignment        alignment;
  1091.     WEActionKind    actionKind;
  1092.     TextStyle        ts;
  1093.     Boolean            temp;
  1094.  
  1095.     
  1096.     gMenuBar->EnableCommand ( cSave,  WEGetModCount(fWEHandle) );
  1097.     gMenuBar->EnableCommand ( cSaveAs, true );
  1098.     gMenuBar->EnableCommand ( cClose, true );
  1099.  
  1100.     actionKind = WEGetUndoInfo( &temp, fWEHandle );
  1101.     gMenuBar->EnableCommand ( cUndo, ( actionKind != weAKNone ) );
  1102.             
  1103.     gMenuBar->EnableCommand ( cCut, HaveSelection() );
  1104.     gMenuBar->EnableCommand ( cCopy,  HaveSelection() );
  1105.     gMenuBar->EnableCommand ( cPaste, WECanPaste( fWEHandle ) );
  1106.     gMenuBar->EnableCommand ( cClear, HaveSelection() );
  1107.     gMenuBar->EnableCommand ( cSelectAll, ( WEGetTextLength( fWEHandle ) != 0 ));
  1108.     
  1109.     
  1110.     mode = weDoAll;  // query about all attributes
  1111.     temp = WEContinuousStyle( &mode, &ts, fWEHandle );
  1112.     
  1113.     if ( mode & weDoFont )
  1114.         {
  1115.         WEStyleMode        mode;
  1116.         TextStyle        ts;
  1117.         short            item;
  1118.         Str255            itemText;
  1119.         MenuRef            menu = GetMenuHandle( mFont );
  1120.         
  1121.         mode = weDoFont;  // query about all attributes
  1122.         WEContinuousStyle( &mode, &ts, fWEHandle );
  1123.  
  1124.         // first, remove all check marks
  1125.         
  1126.         for ( item = CountMItems( menu ); item >= 1; item-- )
  1127.             CheckItem( menu, item, false );
  1128.         
  1129.         // if there is a continuous font all over the selection range, check the
  1130.         // corresponding menu item
  1131.         
  1132.         if ( ( mode & weDoFont ) != 0 )
  1133.             {
  1134.             GetFontName( ts.tsFont, itemText );
  1135.             CheckItem( menu, FindMenuItemText( menu, itemText ), true );
  1136.             }
  1137.         }
  1138.  
  1139.     if ( mode & weDoSize )
  1140.         {
  1141.         gMenuBar->EnableAndCheckCommand( c9Point, true, ( ts.tsSize == 9 ) );
  1142.         gMenuBar->EnableAndCheckCommand( c10Point, true, ( ts.tsSize == 10 ) );
  1143.         gMenuBar->EnableAndCheckCommand( c12Point, true, ( ts.tsSize == 12 ) );
  1144.         gMenuBar->EnableAndCheckCommand( c14Point, true, ( ts.tsSize == 14 ) );
  1145.         gMenuBar->EnableAndCheckCommand( c18Point, true, ( ts.tsSize == 18 ) );
  1146.         gMenuBar->EnableAndCheckCommand( c24Point, true, ( ts.tsSize == 24 ) );
  1147.         gMenuBar->EnableAndCheckCommand( c36Point, true, ( ts.tsSize == 36 ) );
  1148.         gMenuBar->EnableAndCheckCommand( c48Point, true, ( ts.tsSize == 48 ) );
  1149.         gMenuBar->EnableAndCheckCommand( c72Point, true, ( ts.tsSize == 72 ) );
  1150.         
  1151.         switch (ts.tsSize)
  1152.             {
  1153.             case 9:
  1154.             case 10:
  1155.             case 12:
  1156.             case 14:
  1157.             case 18:
  1158.             case 24:
  1159.             case 36:
  1160.             case 48:
  1161.             case 72:
  1162.                 gMenuBar->EnableAndCheckCommand( cOtherSize, true, false );
  1163.                 break;
  1164.                 
  1165.             default:
  1166.                 gMenuBar->EnableAndCheckCommand( cOtherSize, true, true );
  1167.                 break;
  1168.             }
  1169.             
  1170.         gMenuBar->SetItemStyle(c9Point, RealFont(ts.tsFont, 9) ? outline : 0);
  1171.         gMenuBar->SetItemStyle(c10Point, RealFont(ts.tsFont, 10) ? outline : 0);
  1172.         gMenuBar->SetItemStyle(c12Point, RealFont(ts.tsFont, 12) ? outline : 0);
  1173.         gMenuBar->SetItemStyle(c14Point, RealFont(ts.tsFont, 14) ? outline : 0);
  1174.         gMenuBar->SetItemStyle(c18Point, RealFont(ts.tsFont, 18) ? outline : 0);
  1175.         gMenuBar->SetItemStyle(c24Point, RealFont(ts.tsFont, 24) ? outline : 0);
  1176.         gMenuBar->SetItemStyle(c36Point, RealFont(ts.tsFont, 36) ? outline : 0);
  1177.         gMenuBar->SetItemStyle(c48Point, RealFont(ts.tsFont, 48) ? outline : 0);
  1178.         gMenuBar->SetItemStyle(c72Point, RealFont(ts.tsFont, 72) ? outline : 0);        
  1179.         }
  1180.     
  1181.     if ( mode & weDoFace )
  1182.         {
  1183.         gMenuBar->EnableAndCheckCommand( cPlainText, true, ( ts.tsFace == 0 ) );
  1184.         gMenuBar->EnableAndCheckCommand( cBold, true, ( ts.tsFace & bold ) );
  1185.         gMenuBar->EnableAndCheckCommand( cItalic, true, ( ts.tsFace & italic ) );
  1186.         gMenuBar->EnableAndCheckCommand( cUnderline, true, ( ts.tsFace & underline ) );
  1187.         gMenuBar->EnableAndCheckCommand( cOutline, true, ( ts.tsFace & outline ) );
  1188.         gMenuBar->EnableAndCheckCommand( cShadow, true, ( ts.tsFace & shadow ) );
  1189.         gMenuBar->EnableAndCheckCommand( cCondensed, true, ( ts.tsFace & condense ) );
  1190.         gMenuBar->EnableAndCheckCommand( cExtended, true, ( ts.tsFace & extend ) );
  1191.         }
  1192.         
  1193.     if ( mode & weDoColor )
  1194.         {
  1195.         CommandID color = SelectedColor(ts.tsColor);
  1196.  
  1197.         gMenuBar->EnableAndCheckCommand( cBlack, true, color == cBlack );
  1198.         gMenuBar->EnableAndCheckCommand( cBlue, true, color == cBlue );
  1199.         gMenuBar->EnableAndCheckCommand( cGreen, true, color == cGreen );
  1200.         gMenuBar->EnableAndCheckCommand( cRed, true, color == cRed );
  1201.         gMenuBar->EnableAndCheckCommand( cPink, true, color == cPink );
  1202.         gMenuBar->EnableAndCheckCommand( cOrange, true, color == cOrange );
  1203.         gMenuBar->EnableAndCheckCommand( cBrown, true, color == cBrown );
  1204.         gMenuBar->EnableAndCheckCommand( cOtherColor, true, color == cOtherColor );
  1205.         }
  1206.     else
  1207.         {
  1208.         gMenuBar->EnableAndCheckCommand( cBlack, true, false );
  1209.         gMenuBar->EnableAndCheckCommand( cBlue, true, false );
  1210.         gMenuBar->EnableAndCheckCommand( cGreen, true, false );
  1211.         gMenuBar->EnableAndCheckCommand( cRed, true, false );
  1212.         gMenuBar->EnableAndCheckCommand( cPink, true, false );
  1213.         gMenuBar->EnableAndCheckCommand( cOrange, true, false );
  1214.         gMenuBar->EnableAndCheckCommand( cBrown, true, false );
  1215.         gMenuBar->EnableAndCheckCommand( cOtherColor, true, false );
  1216.         }
  1217.         
  1218.  
  1219.         
  1220.     alignment = WEGetAlignment( fWEHandle );
  1221.     gMenuBar->EnableAndCheckCommand( cAlignDefault, true, ( alignment == weFlushDefault ) );
  1222.     gMenuBar->EnableAndCheckCommand( cAlignLeft, true, ( alignment == weFlushLeft ) );
  1223.     gMenuBar->EnableAndCheckCommand( cAlignCenter, true, ( alignment == weCenter ) );
  1224.     gMenuBar->EnableAndCheckCommand( cAlignRight, true, ( alignment == weFlushRight ) );
  1225.     gMenuBar->EnableAndCheckCommand( cAlignJustify, true, ( alignment == weJustify ) );
  1226. }
  1227.  
  1228.  
  1229.  
  1230. /**********************************************************************************/
  1231.  
  1232.  
  1233.  
  1234. // Return a rectangle that is inset from the portRect by the size of
  1235. // the scrollbars and a little extra margin.
  1236.  
  1237. void TTextWindow::GetWERect(LongRect& teRect)
  1238. {
  1239.     Rect    tempRect;
  1240.     
  1241.     tempRect = GetContentsBounds();
  1242.         
  1243.     LocalToGlobal((Point*) &tempRect.top);
  1244.     LocalToGlobal((Point*) &tempRect.bottom);
  1245.  
  1246.     InsetRect(&tempRect, kTextMargin, kTextMargin);            // adjust for margin
  1247.     tempRect.bottom = tempRect.bottom - kScrollbarAdjust;    // and for the scrollbars
  1248.     tempRect.right = tempRect.right - kScrollbarAdjust;
  1249.     
  1250.     tempRect.top += fToolbarHeight;                            // possibly make room for a toolbar
  1251.  
  1252.     WERectToLongRect(&tempRect, &teRect);
  1253. }
  1254.  
  1255.  
  1256. /**********************************************************************************/
  1257.  
  1258.  
  1259.  
  1260. void    TTextWindow::GetGrowIconRect( Rect *iconRect )
  1261. {
  1262.     Rect portRect = GetWindowPort(fWindow)->portRect;
  1263.     
  1264.     iconRect->top = portRect.bottom - (kScrollbarWidth - 2);
  1265.     iconRect->left = portRect.right - (kScrollbarWidth - 2);
  1266.     iconRect->bottom = portRect.bottom;
  1267.     iconRect->right = portRect.right;
  1268. }
  1269.  
  1270.  
  1271.  
  1272. /**********************************************************************************/
  1273.  
  1274.  
  1275.  
  1276. void    TTextWindow::GetTextRect( Rect *textRect )
  1277. {
  1278.     Rect portRect = GetWindowPort(fWindow)->portRect;
  1279.     
  1280.     textRect->top = fToolbarHeight;
  1281.     textRect->left = 0;
  1282.     textRect->bottom = portRect.bottom - (kScrollbarWidth - 1);
  1283.     textRect->right = portRect.right - (kScrollbarWidth - 1);
  1284.     InsetRect( textRect, kTextMargin, kTextMargin );
  1285. }
  1286.  
  1287.  
  1288.  
  1289. /**********************************************************************************/
  1290.  
  1291.  
  1292.  
  1293. void    TTextWindow::GetScrollBarRect( VHSelect axis, Rect *barRect )
  1294. {
  1295.     Rect portRect = GetWindowPort(fWindow)->portRect;
  1296.     
  1297.     switch ( axis )
  1298.     {
  1299.         case v:
  1300.             barRect->top = -1 + fToolbarHeight;
  1301.             barRect->left = portRect.right - (kScrollbarWidth - 1);
  1302.             barRect->bottom = portRect.bottom - (kScrollbarWidth - 2);
  1303.             barRect->right = portRect.right + 1;
  1304.             break;
  1305.  
  1306.         case h:
  1307.             barRect->top = portRect.bottom - (kScrollbarWidth - 1);
  1308.             barRect->left = -1;
  1309.             barRect->bottom = portRect.bottom + 1;
  1310.             barRect->right = portRect.right - (kScrollbarWidth - 2 );
  1311.             break;
  1312.         
  1313.         default:
  1314.             break;
  1315.     }
  1316. }
  1317.  
  1318.  
  1319.  
  1320. /**********************************************************************************/
  1321.  
  1322.  
  1323.  
  1324. // Return boolean value indicating that there is or is not a
  1325. // selection in the document
  1326.  
  1327. Boolean TTextWindow::HaveSelection()
  1328. {
  1329.     long    start, end;
  1330.     
  1331.     
  1332.     WEGetSelection(&start, &end, fWEHandle);
  1333.     
  1334.     if ( start < end )
  1335.         return true;
  1336.     else
  1337.         return false;
  1338. }
  1339.  
  1340.  
  1341.  
  1342.  
  1343. /**********************************************************************************/
  1344.  
  1345.  
  1346.  
  1347.  
  1348. Boolean TTextWindow::DoMenuSelection(short menu, short item)
  1349. {
  1350.     if (menu == mFont)
  1351.         {
  1352.         Str255            fontName;
  1353.         TextStyle        ts;
  1354.  
  1355.         GetMenuItemText( GetMenuHandle( mFont ), item, fontName );
  1356.         GetFNum( fontName, &ts.tsFont );
  1357.         if ( WESetStyle( weDoFont, &ts, fWEHandle ) != noErr )
  1358.             return true;
  1359.         }
  1360.         
  1361.     return TWindow::DoMenuSelection(menu, item);
  1362. }
  1363.  
  1364.  
  1365.  
  1366.  
  1367. /**********************************************************************************/
  1368.  
  1369.  
  1370.  
  1371.  
  1372. Boolean TTextWindow::DoCommand(CommandID theCommand)
  1373. {
  1374.     WEStyleMode        mode = weDoSize;
  1375.     TextStyle        ts;
  1376.     Boolean            restyle = false;
  1377.  
  1378.     switch(theCommand)
  1379.         {
  1380.         case cUndo:
  1381.             if ( WEUndo(fWEHandle) != noErr )
  1382.                 return true;
  1383.             break;
  1384.                 
  1385.         case cCut:
  1386.             if ( WECut(fWEHandle) != noErr )
  1387.                 return true;
  1388.             break;
  1389.             
  1390.         case cCopy:
  1391.             if ( WECopy(fWEHandle) != noErr )
  1392.                 return true;
  1393.             break;
  1394.             
  1395.         case cPaste:
  1396.             if ( WEPaste(fWEHandle) != noErr )
  1397.                 return true;
  1398.             break;
  1399.                     
  1400.         case cSelectAll:
  1401.             WESetSelection( 0, LONG_MAX, fWEHandle );
  1402.             return true;
  1403.             break;
  1404.             
  1405.         case cClear:
  1406.             if ( WEDelete(fWEHandle) != noErr )
  1407.                 return true;
  1408.             break;
  1409.             
  1410.         case c9Point:
  1411.             ts.tsSize = 9;
  1412.             restyle = true;
  1413.             break;
  1414.  
  1415.         case c10Point:
  1416.             ts.tsSize = 10;
  1417.             restyle = true;
  1418.             break;
  1419.  
  1420.         case c12Point:
  1421.             ts.tsSize = 12;
  1422.             restyle = true;
  1423.             break;
  1424.  
  1425.         case c14Point:
  1426.             ts.tsSize = 14;
  1427.             restyle = true;
  1428.             break;
  1429.  
  1430.         case c18Point:
  1431.             ts.tsSize = 18;
  1432.             restyle = true;
  1433.             break;
  1434.  
  1435.         case c24Point:
  1436.             ts.tsSize = 24;
  1437.             restyle = true;
  1438.             break;
  1439.  
  1440.         case c36Point:
  1441.             ts.tsSize = 36;
  1442.             restyle = true;
  1443.             break;
  1444.  
  1445.         case c48Point:
  1446.             ts.tsSize = 48;
  1447.             restyle = true;
  1448.             break;
  1449.             
  1450.         case c72Point:
  1451.             ts.tsSize = 72;
  1452.             restyle = true;
  1453.             break;
  1454.         
  1455.         case cOtherSize:
  1456.             {
  1457.             DialogRef    theDialog = GetNewDialog(260, nil, (WindowRef)-1);
  1458.             if (theDialog)
  1459.                 {
  1460.                 short    itemHit = 0;
  1461.                 Str255    theSize;
  1462.                 long    pointSize;
  1463.                 
  1464.                 ShowWindow(GetDialogWindow(theDialog));
  1465.                 
  1466.                 while (itemHit != 1 && itemHit != 2)
  1467.                     {
  1468.                     ModalDialog(nil, &itemHit);
  1469.                     }
  1470.                     
  1471.                 GetEditText(theDialog, 3, theSize);
  1472.                 StringToNum(theSize, &pointSize);
  1473.                     
  1474.                 HideWindow(GetDialogWindow(theDialog));
  1475.                 DisposeDialog(theDialog);
  1476.                 
  1477.                 if (itemHit == 1 && pointSize > 3 && pointSize < 500 )
  1478.                     {
  1479.                     ts.tsSize = pointSize;
  1480.                     restyle = true;
  1481.                     }
  1482.                 }
  1483.             }
  1484.             break;
  1485.  
  1486.         case cOtherColor:
  1487.             {
  1488.             Point            where = {-1, -1};
  1489.             unsigned short    localMode = doColor;
  1490.             
  1491.             if (!WEContinuousStyle(&localMode, &ts, fWEHandle))
  1492.                 {
  1493.                 ts.tsColor.red = 0xFFFF;
  1494.                 ts.tsColor.green = 0xFFFF;
  1495.                 ts.tsColor.blue = 0xFFFF;
  1496.                 }
  1497.             GetColor(where, "\pPick a text color:", &ts.tsColor, &ts.tsColor);
  1498.             restyle = true;
  1499.             mode = weDoColor;
  1500.             }
  1501.             break;
  1502.             
  1503.         case cBlack:
  1504.             ts.tsColor.red = 0x0000;
  1505.             ts.tsColor.green = 0x0000;
  1506.             ts.tsColor.blue = 0x0000;
  1507.             restyle = true;
  1508.             mode = weDoColor;
  1509.             break;
  1510.             
  1511.         case cBrown:
  1512.             ts.tsColor.red = 42253;
  1513.             ts.tsColor.green = 30947;
  1514.             ts.tsColor.blue = 0;
  1515.             restyle = true;
  1516.             mode = weDoColor;
  1517.             break;
  1518.             
  1519.         case cBlue:
  1520.             ts.tsColor.red = 0;
  1521.             ts.tsColor.green = 0;
  1522.             ts.tsColor.blue = 54272;
  1523.             restyle = true;
  1524.             mode = weDoColor;
  1525.             break;
  1526.             
  1527.         case cGreen:
  1528.             ts.tsColor.red = 0;
  1529.             ts.tsColor.green = 32768;
  1530.             ts.tsColor.blue = 4528;
  1531.             restyle = true;
  1532.             mode = weDoColor;
  1533.             break;
  1534.             
  1535.         case cRed:
  1536.             ts.tsColor.red = 56683;
  1537.             ts.tsColor.green = 2242;
  1538.             ts.tsColor.blue = 1698;
  1539.             restyle = true;
  1540.             mode = weDoColor;
  1541.             break;
  1542.             
  1543.         case cPink:
  1544.             ts.tsColor.red = 65535;
  1545.             ts.tsColor.green = 0;
  1546.             ts.tsColor.blue = 52428;
  1547.             restyle = true;
  1548.             mode = weDoColor;
  1549.             break;
  1550.             
  1551.         case cOrange:
  1552.             ts.tsColor.red = 65535;
  1553.             ts.tsColor.green = 27594;
  1554.             ts.tsColor.blue = 0;
  1555.             restyle = true;
  1556.             mode = weDoColor;
  1557.             break;
  1558.  
  1559.         case cPlainText:
  1560.             mode = weDoFace + weDoToggleFace;
  1561.             ts.tsFace = 0;
  1562.             restyle = true;
  1563.             break;
  1564.         
  1565.         case cBold:
  1566.             ts.tsFace = bold;
  1567.             mode = weDoFace + weDoToggleFace;
  1568.             restyle = true;
  1569.             break;
  1570.         
  1571.         case cItalic:
  1572.             ts.tsFace = italic;
  1573.             mode = weDoFace + weDoToggleFace;
  1574.             restyle = true;
  1575.             break;
  1576.         
  1577.         case cUnderline:
  1578.             ts.tsFace = underline;
  1579.             mode = weDoFace + weDoToggleFace;
  1580.             restyle = true;
  1581.             break;
  1582.         
  1583.         case cOutline:
  1584.             ts.tsFace = outline;
  1585.             mode = weDoFace + weDoToggleFace;
  1586.             restyle = true;
  1587.             break;
  1588.         
  1589.         case cShadow:
  1590.             ts.tsFace = shadow;
  1591.             mode = weDoFace + weDoToggleFace;
  1592.             restyle = true;
  1593.             break;
  1594.         
  1595.         case cCondensed:
  1596.             ts.tsFace = condense;
  1597.             mode = weDoFace + weDoToggleFace;
  1598.             restyle = true;
  1599.             break;
  1600.         
  1601.         case cExtended:
  1602.             ts.tsFace = extend;
  1603.             mode = weDoFace + weDoToggleFace;
  1604.             restyle = true;
  1605.             break;
  1606.             
  1607.         case cAlignLeft:
  1608.             WESetAlignment( weFlushLeft, fWEHandle );
  1609.             return true;
  1610.             break;
  1611.         
  1612.         case cAlignCenter:
  1613.             WESetAlignment( weCenter, fWEHandle );
  1614.             return true;
  1615.             break;
  1616.         
  1617.         case cAlignRight:
  1618.             WESetAlignment( weFlushRight, fWEHandle );
  1619.             return true;
  1620.             break;
  1621.             
  1622.         case cAlignDefault:
  1623.             WESetAlignment( weFlushDefault, fWEHandle );
  1624.             return true;
  1625.             break;
  1626.         
  1627.         case cAlignJustify:
  1628.             WESetAlignment( weJustify, fWEHandle );
  1629.             return true;
  1630.             break;
  1631.     
  1632.         case cSave:
  1633.             {
  1634.             FSSpec    filespec;
  1635.             
  1636.             fBackingFile->GetSpecifier(filespec);
  1637.             if (filespec.name[0] == 0)
  1638.                 return this->DoCommand(cSaveAs);
  1639.             else
  1640.                 {
  1641.                 OSErr    err;
  1642.                 
  1643.                 err = SafeSaveFile(true, filespec);
  1644.                 
  1645.                 // display an alert box if anything went wrong
  1646.                 if (err != noErr)
  1647.                     {
  1648.                     Str255    errorNum;
  1649.                     
  1650.                     NumToString(err, errorNum);
  1651.                     ParamText("\pError #", errorNum, "\p encountered while trying to save the file.", "\p");
  1652.                     StandardAlert( 128 );
  1653.                     }
  1654.                 else
  1655.                     {
  1656.                     pcpy(fName, filespec.name);
  1657.                     SetWTitle(fWindow, fName);
  1658.                     }
  1659.                 }
  1660.  
  1661.             return true;
  1662.             }
  1663.             break;
  1664.             
  1665.         case cSaveAs:
  1666.             {
  1667.             StandardFileReply    reply;
  1668.             OSErr                err;
  1669.             StScrpHandle        hStyles = NULL;
  1670.             WESoupHandle        hSoup = NULL;    
  1671.             
  1672.             
  1673.             StandardPutFile("\pSave this document as:", this->fName, &reply);
  1674.             if (!reply.sfGood)
  1675.                 return true;
  1676.                 
  1677.             err = SafeSaveFile(reply.sfReplacing, reply.sfFile);
  1678.             if (err != noErr)
  1679.                 {
  1680.                 Str255    errorNum;
  1681.                 
  1682.                 NumToString(err, errorNum);
  1683.                 ParamText("\pError #", errorNum, "\p encountered while trying to save the file.", "\p");
  1684.                 StandardAlert( 128 );
  1685.                 }
  1686.             else
  1687.                 {
  1688.                 pcpy(fName, reply.sfFile.name);
  1689.                 SetWTitle(fWindow, fName);
  1690.                 }
  1691.  
  1692.             return true;
  1693.             }
  1694.             break;
  1695.         }
  1696.  
  1697.  
  1698.     if (restyle)
  1699.         {
  1700.         if ( WESetStyle( mode, &ts, fWEHandle ) != noErr )
  1701.             return true;
  1702.         }
  1703.  
  1704.     return TWindow::DoCommand(theCommand);
  1705. }
  1706.  
  1707.  
  1708.  
  1709. /**********************************************************************************/
  1710.  
  1711.  
  1712.  
  1713. static pascal void TextScrolled( WEReference we )
  1714. {
  1715.     TTextWindow*    This;
  1716.     
  1717.     //    retrieve the TTextWindow pointer stored in the WE instance as a "reference constant"
  1718.     
  1719.     if (WEGetInfo(weRefCon, &This, we) != noErr )
  1720.         return;
  1721.     
  1722.     //    make sure the scroll bars are in synch with the destination rectangle
  1723.     
  1724.     This->AdjustBars();
  1725.  
  1726.     return;
  1727. }
  1728.  
  1729.  
  1730.  
  1731. /**********************************************************************************/
  1732.  
  1733.  
  1734.  
  1735. void TTextWindow::DoScrollKey( SignedByte keyCode )
  1736. {
  1737.     ControlRef            bar;
  1738.     long                v;
  1739.     LongRect            viewRect;
  1740.     
  1741.     bar = fDocVScroll;
  1742.  
  1743.     //    get current scroll bar value
  1744.     
  1745.     v = LCGetValue( bar );
  1746.     
  1747.     //    get text view rect
  1748.     
  1749.     WEGetViewRect( &viewRect, fWEHandle );
  1750.     
  1751.     switch ( keyCode )
  1752.     {
  1753.     
  1754.         case keyPgUp:
  1755.             v -= ( viewRect.bottom - viewRect.top ) + kScrollDelta;        
  1756.             break;
  1757.         
  1758.         case keyPgDn:
  1759.             v += ( viewRect.bottom - viewRect.top ) - kScrollDelta;
  1760.             break;
  1761.  
  1762.         case keyHome:
  1763.             v = 0;
  1764.             break;
  1765.         
  1766.         case keyEnd:
  1767.             v = LONG_MAX;
  1768.             break;
  1769.         
  1770.         default:
  1771.             break;
  1772.     }    // end switch keyCode
  1773.     
  1774.     
  1775.     //    set the new scroll bar value and scroll the text pane accordingly
  1776.     
  1777.     LCSetValue( bar, v );
  1778.     ScrollBarChanged();
  1779. }
  1780.  
  1781.  
  1782.  
  1783. /**********************************************************************************/
  1784.  
  1785.  
  1786.  
  1787.  
  1788. void    TTextWindow::DoScrollBar( Point hitPt, EventModifiers modifiers )
  1789. {
  1790.     ControlRef            bar;
  1791.     LongRect            viewRect;
  1792.     ControlPartCode        partCode;
  1793.     short                step;
  1794.     
  1795.     WEGetViewRect(&viewRect, fWEHandle);
  1796.     //    find out which scrollbar was hit (if any) and in which part
  1797.     partCode = FindControl( hitPt, fWindow, &bar );
  1798.     
  1799.     if ( bar != NULL )
  1800.         {
  1801.         //    dispatch on partCode
  1802.     
  1803.         if ( partCode == kControlIndicatorPart )
  1804.             {
  1805.             // click in thumb: call TrackControl with no actionProc and adjust text
  1806.             
  1807.             partCode = TrackControl( bar, hitPt, NULL );
  1808.             LCSynch( bar );
  1809.             this->ScrollBarChanged();
  1810.             
  1811.             } // end if partCode == kControlIndicatorPart    
  1812.         else
  1813.             {
  1814.             if ( bar == fDocVScroll )
  1815.                 {
  1816.             
  1817.                 // dispatch our partCode
  1818.             
  1819.                 switch( partCode )
  1820.                     {
  1821.                     case kControlUpButtonPart:
  1822.                         if ( (modifiers & optionKey ) == 0 )
  1823.                             step = -kScrollDelta;
  1824.                         else
  1825.                             step = -1;
  1826.                         break;
  1827.                 
  1828.                     case kControlDownButtonPart:
  1829.                         if ( (modifiers & optionKey ) == 0 )
  1830.                             step = +kScrollDelta;
  1831.                         else
  1832.                             step = 1;
  1833.                         break;
  1834.                 
  1835.                     case kControlPageUpPart:
  1836.                         step = -( viewRect.bottom - viewRect.top) + kScrollDelta;
  1837.                         break;
  1838.                 
  1839.                     case kControlPageDownPart:
  1840.                         step = ( viewRect.bottom - viewRect.top ) - kScrollDelta;
  1841.                         break;
  1842.                 
  1843.                     default:
  1844.                         step = 0;
  1845.                         break;
  1846.                     }
  1847.                 }
  1848.             else if ( bar == fDocHScroll )
  1849.                 {
  1850.             
  1851.                 // dispatch our partCode
  1852.             
  1853.                 switch( partCode )
  1854.                     {
  1855.                     case kControlUpButtonPart:
  1856.                         if ( (modifiers & optionKey ) == 0 )
  1857.                             step = -kScrollDelta;
  1858.                         else
  1859.                             step = -1;
  1860.                         break;
  1861.                 
  1862.                     case kControlDownButtonPart:
  1863.                         if ( (modifiers & optionKey ) == 0 )
  1864.                             step = +kScrollDelta;
  1865.                         else
  1866.                             step = 1;
  1867.                         break;
  1868.                 
  1869.                     case kControlPageUpPart:
  1870.                         step = -( viewRect.right - viewRect.left) + kScrollDelta;
  1871.                         break;
  1872.                 
  1873.                     case kControlPageDownPart:
  1874.                         step = ( viewRect.right - viewRect.left ) - kScrollDelta;
  1875.                         break;
  1876.                 
  1877.                     default:
  1878.                         step = 0;
  1879.                         break;
  1880.                     }
  1881.                 }
  1882.     
  1883.             //    save step in a static variable for our ScrollProc callback
  1884.         
  1885.             sScrollStep = step;
  1886.         
  1887.             //    track the mouse
  1888.         
  1889.             if ( sScrollProc == NULL )
  1890.                 sScrollProc = NewControlActionProc( ScrollProc );
  1891.             partCode = TrackControl( bar, hitPt, sScrollProc );
  1892.             }
  1893.  
  1894.         }
  1895. }
  1896.  
  1897.  
  1898.  
  1899. /**********************************************************************************/
  1900.  
  1901.  
  1902.  
  1903. // this is a callback routine called by the Toolbox Control Manager
  1904. // move the scroll bar thumb and scroll the text accordingly
  1905.  
  1906. static pascal void ScrollProc( ControlRef bar, ControlPartCode partCode )
  1907. {
  1908.     long        value, step;
  1909.  
  1910.     if ( partCode == kControlNoPart )
  1911.         return;
  1912.     
  1913.     value = LCGetValue( bar );
  1914.     step = sScrollStep;
  1915.  
  1916.     if ( (( value < LCGetMax( bar )) && ( step > 0 )) || (( value > 0 ) && ( step < 0 ) ) )
  1917.         {
  1918.         LCSetValue( bar, value + step );
  1919.         
  1920.         TTextWindow*    This = (TTextWindow*)GetWRefCon(FrontWindow());
  1921.         This->ScrollBarChanged();
  1922.         }
  1923. }
  1924.  
  1925.  
  1926.  
  1927. OSErr TTextWindow::DragEnterWindow(DragReference theDrag)
  1928. {
  1929.     return WETrackDrag( dragTrackingEnterWindow, theDrag, fWEHandle );
  1930. }
  1931.  
  1932.  
  1933. OSErr TTextWindow::DragInWindow(DragReference theDrag)
  1934. {
  1935.     return WETrackDrag( dragTrackingInWindow, theDrag, fWEHandle );
  1936. }
  1937.  
  1938.  
  1939. OSErr TTextWindow::DragLeaveWindow(DragReference theDrag)
  1940. {
  1941.     return WETrackDrag( dragTrackingLeaveWindow, theDrag, fWEHandle );
  1942. }
  1943.     
  1944.  
  1945. OSErr TTextWindow::HandleDrop(DragReference  theDrag)
  1946. {
  1947.     return WEReceiveDrag( theDrag, fWEHandle );
  1948. }
  1949.  
  1950.  
  1951.  
  1952. /**********************************************************************************/
  1953.  
  1954.  
  1955.  
  1956. pascal OSErr    TranslateDrag( DragReference theDrag, ItemReference theItem, FlavorType requestedType, Handle dataHandle )
  1957. {
  1958. #pragma unused ( theDrag, theItem, dataHandle )
  1959.  
  1960.     if ( ( requestedType != kTypeText ) && ( requestedType != kTypeTextReadOnly ) )
  1961.         return badDragFlavorErr;
  1962.     
  1963.     return noErr;
  1964. }
  1965.  
  1966.  
  1967.  
  1968. /**********************************************************************************/
  1969.  
  1970.  
  1971.  
  1972. static short    FindMenuItemText( MenuRef menu, ConstStr255Param stringToFind )
  1973. {
  1974.     short        item;
  1975.     Str255        itemString;
  1976.     
  1977.     for ( item = CountMItems( menu ); item >= 1; item-- )
  1978.         {
  1979.         GetMenuItemText( menu, item, itemString );
  1980.         if ( EqualString( itemString, stringToFind, false, false ) )
  1981.             break;
  1982.         }
  1983.     
  1984.     return item;
  1985. }
  1986.  
  1987.  
  1988.  
  1989.  
  1990. /**********************************************************************************/
  1991.  
  1992.  
  1993.  
  1994. OSErr TTextWindow::SafeSaveFile(Boolean replacing, FSSpec& filespec)
  1995. {
  1996.     FInfo            fileInfo;
  1997.     Size            textSize;
  1998.     OSStatus        err = noErr;
  1999.     OSErr            tempErr = noErr;
  2000.     short            dataForkRefNum = 0;
  2001.     short            resForkRefNum = 0;
  2002.     Handle            hText = NULL;
  2003.     StScrpHandle    hStyles = NULL;
  2004.     WESoupHandle    hSoup = NULL;    
  2005.     unsigned long    theTime;
  2006.     Str255            tempFileName;
  2007.     FSSpec            tempFileSpec;
  2008.     short            tempVRef;        // volume reference # for the temp file
  2009.     long            tempDirID;        // directory ID of the temp file
  2010.     
  2011.     TFile*            tempFile;
  2012.  
  2013.  
  2014.     //    will we be replacing an existing file?
  2015.     
  2016.     if ( replacing )
  2017.         {
  2018.         err = CheckObjectLock(filespec.vRefNum, filespec.parID, (StringPtr) filespec.name);
  2019.         if ( err != noErr ) // if it returns noErr, the file/directory is NOT locked
  2020.             return err;
  2021.     
  2022.         // create the temporary file name.  the name doesn't have to make sense, just
  2023.         // be unique
  2024.         
  2025.         GetDateTime( &theTime );
  2026.         NumToString( theTime, tempFileName );
  2027.     
  2028.         // find the temporary items folder on the file's volume; create it if necessary
  2029.         // it is important that the temp folder (and the temp file) and the "original" target
  2030.         // file be on the same volume; if not, FSpExchangeFiles will return diffVolErr (-1303)
  2031.         // and won't work
  2032.         
  2033.         err = FindFolder( filespec.vRefNum, kTemporaryFolderType, kCreateFolder, &tempVRef, &tempDirID );
  2034.         if ( err != noErr )
  2035.             return err;  // for now, do nothing, just return        
  2036.         
  2037.         // make an FSSpec for the temp file
  2038.         
  2039.         err = FSMakeFSSpec( tempVRef, tempDirID, tempFileName, &tempFileSpec );
  2040.         if ( (err != noErr) && (err != fnfErr ) )
  2041.             return err;
  2042.             
  2043.         tempFile = new TFile(tempFileSpec);
  2044.         }
  2045.     else
  2046.         fBackingFile->SetSpecifier(filespec);
  2047.  
  2048.     //    create a new file.  if we're replacing, make a temp file.  if it's a
  2049.     //  new file from the onset, just create the file
  2050.     
  2051.     // should we allow people to choose the file to create?  i.e. create a TEXT
  2052.     // file or a ttro file?  if you'd like to do this, you'll want to find this
  2053.     // info out when calling CustomPutFile() and pass that info to this function
  2054.     
  2055.     if ( replacing )
  2056.         err = tempFile->CreateNewFile('trsh', 'trsh', smSystemScript );
  2057.     else
  2058.         err = fBackingFile->CreateNewFile('75SL', kTypeText, smSystemScript );
  2059.     
  2060.     err = ResError();
  2061.     if ( err != noErr )
  2062.         goto cleanup;
  2063.     
  2064.     //  if replacing an old file, copy the old file information
  2065.     if ( replacing )
  2066.     {
  2067.         err = FSpSetFInfo( &tempFileSpec, &fileInfo );
  2068.         if ( err != noErr )
  2069.         {
  2070.             goto cleanup;
  2071.         }
  2072.     }
  2073.     
  2074.         
  2075.     //    open the data fork for writing
  2076.     if ( replacing )
  2077.         dataForkRefNum = tempFile->OpenDataFork(fsWrPerm);
  2078.     else
  2079.         dataForkRefNum = fBackingFile->OpenDataFork(fsWrPerm);
  2080.         
  2081.     if ( err != noErr )
  2082.         goto cleanup;
  2083.     
  2084.     //    set the end-of-file
  2085.     
  2086.     err = SetEOF( dataForkRefNum, 0 );
  2087.     if ( err != noErr )
  2088.         goto cleanup;
  2089.         
  2090.     //    get the text handle from the WE instance
  2091.     //    WEGetText returns the original handle, not a copy, so don't dispose of it!!
  2092.     hText = WEGetText( fWEHandle );
  2093.     textSize = GetHandleSize( hText );
  2094.     
  2095.     //    write the text
  2096.     HLock( hText );
  2097.     if (replacing)
  2098.         textSize = tempFile->WriteDataFork(*hText, textSize);
  2099.     else
  2100.         textSize = fBackingFile->WriteDataFork(*hText, textSize);
  2101.     HUnlock( hText );
  2102.  
  2103.     if ( textSize == 0 )
  2104.         {
  2105.         err = eofErr;
  2106.         goto cleanup;
  2107.         }
  2108.         
  2109.     if (replacing)
  2110.         err = tempFile->CloseDataFork();
  2111.     else
  2112.         err = fBackingFile->CloseDataFork();
  2113.     
  2114.     //    open the resource file for writing
  2115.     
  2116.     if ( replacing )
  2117.         resForkRefNum = tempFile->OpenResourceFork( fsWrPerm );
  2118.     else
  2119.         resForkRefNum = fBackingFile->OpenResourceFork( fsWrPerm );
  2120.         
  2121.     err = ResError();
  2122.     if ( err != noErr )
  2123.         goto cleanup;
  2124.     
  2125.     //    allocate temporary handles to hold the style scrap and the soup
  2126.     //    try tapping temporary memory since WECopyRange() could get huge
  2127.  
  2128.     hStyles = (StScrpHandle)TempNewHandle( 0, &tempErr );
  2129.     if ( tempErr != noErr )
  2130.         {
  2131.         err = tempErr;
  2132.         goto cleanup;
  2133.         }
  2134.  
  2135.     hSoup = (WESoupHandle)TempNewHandle( 0, &tempErr );
  2136.     if ( tempErr != noErr )
  2137.         {
  2138.         err = tempErr;
  2139.         goto cleanup;
  2140.         }
  2141.  
  2142.     //    create the style scrap and the soup
  2143.     
  2144.  
  2145.     err = WECopyRange( 0, LONG_MAX, NULL, hStyles, hSoup, fWEHandle );
  2146.     if ( err != noErr )
  2147.         goto cleanup;
  2148.  
  2149.     
  2150.     //    make them resource handles
  2151.     
  2152.     err = RMAddResourceCompat( (Handle)hStyles, kTypeStyles, 128, "\p" );
  2153.     if ( err != noErr )
  2154.         goto cleanup;
  2155.     
  2156.     err = RMAddResourceCompat( (Handle)hSoup, kTypeSoup, 128, "\p" );
  2157.     if ( err != noErr )
  2158.         goto cleanup;
  2159.  
  2160.     //    write them to the resource file
  2161.     
  2162.     err = RMChangedResourceCompat( (Handle)hStyles );
  2163.     if ( err != noErr )
  2164.         goto cleanup;
  2165.  
  2166.     err = RMWriteResourceCompat( (Handle)hStyles );
  2167.     if ( err != noErr )
  2168.         goto cleanup;
  2169.  
  2170.     err = RMChangedResourceCompat( (Handle)hSoup );
  2171.     if ( err != noErr )
  2172.         goto cleanup;
  2173.  
  2174.     err = RMWriteResourceCompat( (Handle)hSoup );
  2175.     if ( err != noErr )
  2176.         goto cleanup;
  2177.         
  2178.     if ( replacing )
  2179.         err = tempFile->CloseResourceFork();
  2180.     else
  2181.         err = fBackingFile->CloseResourceFork();
  2182.  
  2183.     if ( err != noErr )
  2184.         goto cleanup;
  2185.     
  2186.  
  2187.     //    "clean" this document by resetting the WE instance modification count
  2188.     
  2189.     WEResetModCount( fWEHandle );
  2190.     
  2191.     err = noErr;
  2192.     
  2193.     //    clean up
  2194.  
  2195. cleanup:
  2196.  
  2197.     // remember, don't dispose the hText handle!
  2198.     
  2199.     if (hStyles)
  2200.         DisposeHandle( (Handle) hStyles );
  2201.         
  2202.     if (hSoup)
  2203.         DisposeHandle( (Handle) hSoup );
  2204.     
  2205.     if ( replacing )
  2206.         {
  2207.         // since we were replacing an existing file, let's now swap the original
  2208.         // and the temp file.  let's hear it for safe saves.
  2209.         
  2210.         err = FSpExchangeFiles( &tempFileSpec, &filespec );
  2211.         if ( err != noErr )
  2212.             return err;
  2213.         
  2214.         // can the temp file since we don't need it anymore
  2215.         
  2216.         tempFile->SetSpecifier(tempFileSpec);
  2217.         err = tempFile->Delete();
  2218.         if ( err != noErr )
  2219.             return err;            
  2220.  
  2221.         delete tempFile;
  2222.         }
  2223.     
  2224.     // and update the disk with any unwritten data
  2225.     
  2226.     FlushVol( "\p", filespec.vRefNum );
  2227.     
  2228.     return err;
  2229. }
  2230.  
  2231.  
  2232.  
  2233. static CommandID    SelectedColor(RGBColor& theColor)
  2234. {
  2235.     if (theColor.red == 0x0000 && theColor.green == 0x0000 && theColor.blue == 0x0000)
  2236.         return cBlack;
  2237.         
  2238.     if (theColor.red == 42253 && theColor.green == 30947 && theColor.blue == 0x0000)
  2239.         return cBrown;
  2240.         
  2241.     if (theColor.red == 0x0000 && theColor.green == 0x0000 && theColor.blue == 54272)
  2242.         return cBlue;
  2243.         
  2244.     if (theColor.red == 0x0000 && theColor.green == 32768 && theColor.blue == 4528)
  2245.         return cGreen;
  2246.         
  2247.     if (theColor.red == 56683 && theColor.green == 2242 && theColor.blue == 1698)
  2248.         return cRed;
  2249.         
  2250.     if (theColor.red == 65535 && theColor.green == 0x0000 && theColor.blue == 52428)
  2251.         return cPink;
  2252.         
  2253.     if (theColor.red == 65535 && theColor.green == 27594 && theColor.blue == 0x0000)
  2254.         return cOrange;
  2255.         
  2256.     return cOtherColor;
  2257. }
  2258.  
  2259.  
  2260.  
  2261.